package com.cnebula.openapi.auth.authtoken.impl;

import com.cnebula.openapi.auth.authtoken.UserInfo;
import com.cnebula.openapi.auth.authtoken.UserService;

import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpClient;
import io.vertx.core.http.HttpClientOptions;
import io.vertx.core.http.HttpClientRequest;
import io.vertx.core.json.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class UserServiceImpl implements UserService {

	private String okapiUrl = null;
	private Vertx vertx;
	private String requestToken;
	private String tenant;
	private int timeout = 10;
	private final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

	public UserServiceImpl(Vertx vertx) {
		this.vertx = vertx;
	}

	public void setOkapiUrl(String url) {
		okapiUrl = url;
		if (!okapiUrl.endsWith("/")) {
			okapiUrl = okapiUrl + "/";
		}
	}

	public void setRequestToken(String token) {
		requestToken = token;
	}

	public void setTenant(String tenant) {
		this.tenant = tenant;
	}

	public void setRequestTimeout(int seconds) {
		this.timeout = seconds;
	}

	@Override
	public Future<UserInfo> getUserByUserId(String userId) {
		Future<UserInfo> future = Future.future();

		HttpClientOptions options = new HttpClientOptions();
		options.setConnectTimeout(timeout * 1000);
		HttpClient client = vertx.createHttpClient(options);
		String okapiUrlCandidate = "http://localhost:9130/";
		if (okapiUrl != null) {
			okapiUrlCandidate = okapiUrl;
		}
		final String okapiUrlFinal = okapiUrlCandidate;
		String getUserByIdRequestUrl = okapiUrlFinal + "users/" + userId;
		logger.debug("Requesting get user info from URL at " + getUserByIdRequestUrl);

		HttpClientRequest req = client.getAbs(getUserByIdRequestUrl);

		req.handler(h -> {
			h.bodyHandler(res -> {

				if (h.statusCode() == 200) {
					JsonObject userObject;
					try {
						userObject = new JsonObject(res.toString());
					} catch (Exception e) {
						logger.debug("Error parsing user object: " + e.getLocalizedMessage());
						userObject = null;
					}
					if (userObject != null) {
						future.complete(new UserInfo(userObject));
					} else {
						logger.warn("Got empty user object");
						future.fail("Got empty user object");
					}
				} else if (h.statusCode() == 404) {
					// In the event of a 404, that means that the user not found
					future.complete(new UserInfo());
				} else {
					String failMessage = "Unable to retrieve user (code " + h.statusCode() + "): " + res.toString();
					logger.warn(failMessage);
					future.fail(failMessage);
				}
			});

		});
		req.exceptionHandler(e -> {
			future.fail(e);
		});
		req.headers().add("X-Okapi-Token", requestToken);
		req.headers().add("X-Okapi-Tenant", tenant);
		req.headers().add("Content-Type", "application/json");
		req.headers().add("Accept", "application/json");
		req.end();

		return future;
	}

}
